use anyhow::Result;
use std::fs;
use std::io::prelude::*;

pub fn save_data1(path: &str, data: &[u8]) -> Result<usize> {
    let mut fp = fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(true)
        .open(path)?;
    // 设置mode 只在linux 下使用
    // use std::os::unix::fs::OpenOptionsExt;
    // fp.set_mode(0o666);
    let size: usize = fp.write(data)?;
    // fp.close()?;
    Ok(size)
}

// 生成随机数
#[allow(dead_code)]
fn random_int() -> u64 {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    let i: u64 = rng.gen();
    return i;
}
#[allow(dead_code)]
fn save_data2(path: &str, data: &[u8]) -> Result<()> {
    let tmp = format!("{}.tmp.{}", path, random_int());

    let mut fp = fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(true)
        .open(tmp.as_str())?;
    // 设置mode 只在linux 下使用
    // use std::os::unix::fs::OpenOptionsExt;
    // fp.set_mode(0o666);
    let r = fp.write(data);
    // fp.close()?;
    if let Err(e) = r {
        //删除文件
        fs::remove_file(tmp)?;
        return Err(e.into());
    }

    fs::rename(tmp, path)?;
    Ok(())
}
#[allow(dead_code)]
fn save_data3(path: &str, data: &[u8]) -> Result<()> {
    let tmp = format!("{}.tmp.{}", path, random_int());

    let mut fp = fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(true)
        .open(tmp.as_str())?;
    // 设置mode 只在linux 下使用
    // use std::os::unix::fs::OpenOptionsExt;
    // fp.set_mode(0o666);
    let r = fp.write(data);
    // fp.close()?;
    // fp 不用显式关闭，超出作用域回自动销毁
    if let Err(e) = r {
        //删除文件
        fs::remove_file(tmp)?;
        return Err(e.into());
    }

    // sync 数据
    let r = fp.sync_all();
    if let Err(e) = r {
        //删除文件
        fs::remove_file(tmp)?;
        return Err(e.into());
    }

    fs::rename(tmp, path)?;
    Ok(())
}

// 测试代码
#[cfg(test)]
mod tests {
    // 导入上级模块
    use super::*;
    #[test]
    fn test_save_data1() {
        let data = "aaabbbccc";
		let path="d:/a.txt";
        let a = save_data1(path, data.as_bytes());
		fs::remove_file(path).unwrap();
        assert_eq!(a.unwrap(), data.len());
    }
    #[test]
    fn test_save_data2() {
        let data = "aaabbbccc";
		let path="d:/b.txt";
        let a = save_data2(path, data.as_bytes());
		fs::remove_file(path).unwrap();
        assert_eq!(a.unwrap(), ());
    }

    #[test]
    fn test_save_data3() {
        let data = "aaabbbccc";
		let path="d:/c.txt";
        let a = save_data2(path, data.as_bytes());
		fs::remove_file(path).unwrap();
        assert_eq!(a.unwrap(), ());
    }
}
